{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# DrakeVisualizer.jl\n",
    "This notebook demonstrates interacting with the Drake Visualizer app from Julia. On Mac and Ubuntu, just installing `DrakeVisualizer.jl` will also install a pre-built version of the standalone `drake-visualizer` executable. \n",
    "\n",
    "If you're not on one of those platforms, you'll need to install Director (which includes `drake-visualizer`) from <https://github.com/robotlocomotion/director>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Activate the DrakeVisualizer package, and import some other \n",
    "# useful functions\n",
    "using DrakeVisualizer\n",
    "using CoordinateTransformations\n",
    "using Interact, Reactive\n",
    "import GeometryTypes: HyperRectangle, Vec, HomogenousMesh\n",
    "import ColorTypes: RGBA"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Launch the viewer application if it isn't running already:\n",
    "DrakeVisualizer.any_open_windows() || DrakeVisualizer.new_window();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "GeometryTypes.HyperRectangle{3,Float64}(Vec(0.0,0.0,0.0),Vec(1.0,1.0,1.0))"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# First, we'll create a simple geometric object\n",
    "box = HyperRectangle(Vec(0.,0,0), Vec(1.,1,1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Visualizer with path prefix Symbol[] using LCM LCMCore.LCM(Ptr{Void} @0x00007ff953428200,RawFD(47),LCMCore.Subscription[LCMCore.Subscription{LCMCore.SubscriptionOptions{DrakeVisualizer.Comms.CommsT,DrakeVisualizer.#handle_msg#7{DrakeVisualizer.CoreVisualizer}}}(LCMCore.SubscriptionOptions{DrakeVisualizer.Comms.CommsT,DrakeVisualizer.#handle_msg#7{DrakeVisualizer.CoreVisualizer}}(DrakeVisualizer.Comms.CommsT,DrakeVisualizer.handle_msg),Ptr{Void} @0x00007ff957700ae0)])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Visualizer() causes the viewer to spawn a geometry or a set of geometries. \n",
    "# It returns a Visualizer, which includes all the information\n",
    "# about that loaded geometry. \n",
    "# Note that the model is initially loaded in the zero configuration \n",
    "# (that is, its position and rotation are all zeros)\n",
    "model = Visualizer(box)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# We can use settransform!() to tell the viewer to draw the box at a specific\n",
    "# position. Translation() creates a CoordinateTransformations.Transformation\n",
    "# corresponding to the given x; y; z translation.\n",
    "settransform!(model, Translation(1.,0,0))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# We can also rotate the model by sending a different transformation\n",
    "settransform!(model, LinearMap(AngleAxis(pi/4, 0, 0, 1)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# And we can clear the box\n",
    "delete!(model)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Visualizer with path prefix Symbol[] using LCM LCMCore.LCM(Ptr{Void} @0x00007ff95745af00,RawFD(53),LCMCore.Subscription[LCMCore.Subscription{LCMCore.SubscriptionOptions{DrakeVisualizer.Comms.CommsT,DrakeVisualizer.#handle_msg#7{DrakeVisualizer.CoreVisualizer}}}(LCMCore.SubscriptionOptions{DrakeVisualizer.Comms.CommsT,DrakeVisualizer.#handle_msg#7{DrakeVisualizer.CoreVisualizer}}(DrakeVisualizer.Comms.CommsT,DrakeVisualizer.handle_msg),Ptr{Void} @0x00007ff95911f3f0)])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Now let's make some more complicated robots. We'll create a \n",
    "# new GeometryData from the box, but color it green this time.\n",
    "green_box = GeometryData(box, RGBA(0., 1, 0, 0.5))\n",
    "model = Visualizer(green_box)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "delete!(model)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# The Viewer Tree\n",
    "\n",
    "Now that we've introduced the basics of loading and transforming geometries, it's time to introduce the tree model used by DrakeVisualizer.jl. The idea is pretty simple:\n",
    "\n",
    "* A Visualizer contains a *tree* of geometries\n",
    "* We add, draw, and delete geometries by using their *path*, which is the path from the root of the tree to that geometry\n",
    "* We can set the transform for any node in the tree. Setting the transform for a node in the tree affects all of its descendant geometries. \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Visualizer with path prefix Symbol[] using LCM LCMCore.LCM(Ptr{Void} @0x00007ff959113420,RawFD(59),LCMCore.Subscription[LCMCore.Subscription{LCMCore.SubscriptionOptions{DrakeVisualizer.Comms.CommsT,DrakeVisualizer.#handle_msg#7{DrakeVisualizer.CoreVisualizer}}}(LCMCore.SubscriptionOptions{DrakeVisualizer.Comms.CommsT,DrakeVisualizer.#handle_msg#7{DrakeVisualizer.CoreVisualizer}}(DrakeVisualizer.Comms.CommsT,DrakeVisualizer.handle_msg),Ptr{Void} @0x00007ff959122a70)])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# First, we make an empty visualizer:\n",
    "vis = Visualizer()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Visualizer with path prefix Symbol[:group1] using LCM LCMCore.LCM(Ptr{Void} @0x00007ff959113420,RawFD(59),LCMCore.Subscription[LCMCore.Subscription{LCMCore.SubscriptionOptions{DrakeVisualizer.Comms.CommsT,DrakeVisualizer.#handle_msg#7{DrakeVisualizer.CoreVisualizer}}}(LCMCore.SubscriptionOptions{DrakeVisualizer.Comms.CommsT,DrakeVisualizer.#handle_msg#7{DrakeVisualizer.CoreVisualizer}}(DrakeVisualizer.Comms.CommsT,DrakeVisualizer.handle_msg),Ptr{Void} @0x00007ff959122a70)])"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# We can access a particular path within the visualizer with indexing notation:\n",
    "vis[:group1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Visualizer with path prefix Symbol[:group1,:greenbox] using LCM LCMCore.LCM(Ptr{Void} @0x00007ff959113420,RawFD(59),LCMCore.Subscription[LCMCore.Subscription{LCMCore.SubscriptionOptions{DrakeVisualizer.Comms.CommsT,DrakeVisualizer.#handle_msg#7{DrakeVisualizer.CoreVisualizer}}}(LCMCore.SubscriptionOptions{DrakeVisualizer.Comms.CommsT,DrakeVisualizer.#handle_msg#7{DrakeVisualizer.CoreVisualizer}}(DrakeVisualizer.Comms.CommsT,DrakeVisualizer.handle_msg),Ptr{Void} @0x00007ff959122a70)])"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# We load geometries using the same path notation:\n",
    "green_box_vis = setgeometry!(vis[:group1][:greenbox], green_box)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Check out the Scene Browser in the drake visualizer app. You should see folder:\n",
    "\n",
    "    scene\n",
    "      | remote tree viewer\n",
    "          | group1\n",
    "              | greenbox\n",
    "\n",
    "  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# And we set transforms in the same way:\n",
    "settransform!(green_box_vis, Translation(0, 0, 1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# The same indexing notation makes it easy to get a handle to a \n",
    "# particular part of the viewer tree:\n",
    "group1 = vis[:group1]\n",
    "settransform!(group1, Translation(0, 0, -1))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The viewer tree becomes much more interesting (and useful) when we have multiple geometries. Let's add another geometry in the same group:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Visualizer with path prefix Symbol[:group1,:bluebox] using LCM LCMCore.LCM(Ptr{Void} @0x00007ff959113420,RawFD(59),LCMCore.Subscription[LCMCore.Subscription{LCMCore.SubscriptionOptions{DrakeVisualizer.Comms.CommsT,DrakeVisualizer.#handle_msg#7{DrakeVisualizer.CoreVisualizer}}}(LCMCore.SubscriptionOptions{DrakeVisualizer.Comms.CommsT,DrakeVisualizer.#handle_msg#7{DrakeVisualizer.CoreVisualizer}}(DrakeVisualizer.Comms.CommsT,DrakeVisualizer.handle_msg),Ptr{Void} @0x00007ff959122a70)])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "setgeometry!(vis[:group1][:bluebox], GeometryData(box, RGBA(0, 0, 1, 0.5)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The scene browser will now show:\n",
    "\n",
    "    scene\n",
    "      | remote tree viewer\n",
    "          | group1\n",
    "              | greenbox\n",
    "              | bluebox"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Since both the green and blue box are inside `group1`, we can move them together by transforming that whole group:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "settransform!(vis[:group1], Translation(1, 0, 0))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Or we can move just the green box:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "settransform!(vis[:group1][:greenbox], Translation(0, 1, 0))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The final pose of each geometry in the tree is just the composition of all of the transforms in the path from the root of the tree to that geometry. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's try interactively moving the entire group (with the first slider) and also just the green box (with the second slider):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [],
      "text/plain": [
       "Interact.Options{:SelectionSlider,Float64}(Signal{Float64}(0.9795918367346939, nactions=1),\"x1\",0.9795918367346939,\"0.9795918367346939\",Interact.OptionDict(DataStructures.OrderedDict(\"0.0\"=>0.0,\"0.04081632653061224\"=>0.0408163,\"0.08163265306122448\"=>0.0816327,\"0.12244897959183673\"=>0.122449,\"0.16326530612244897\"=>0.163265,\"0.20408163265306123\"=>0.204082,\"0.24489795918367346\"=>0.244898,\"0.2857142857142857\"=>0.285714,\"0.32653061224489793\"=>0.326531,\"0.3673469387755102\"=>0.367347…),Dict(2.0=>\"2.0\",1.59184=>\"1.5918367346938775\",0.122449=>\"0.12244897959183673\",1.95918=>\"1.9591836734693877\",1.22449=>\"1.2244897959183674\",1.63265=>\"1.6326530612244898\",0.693878=>\"0.6938775510204082\",1.10204=>\"1.1020408163265305\",1.79592=>\"1.7959183673469388\",0.367347=>\"0.3673469387755102\"…)),Any[],Any[],true,\"horizontal\")"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [],
      "text/plain": [
       "Interact.Options{:SelectionSlider,Float64}(Signal{Float64}(0.9795918367346939, nactions=1),\"x2\",0.9795918367346939,\"0.9795918367346939\",Interact.OptionDict(DataStructures.OrderedDict(\"0.0\"=>0.0,\"0.04081632653061224\"=>0.0408163,\"0.08163265306122448\"=>0.0816327,\"0.12244897959183673\"=>0.122449,\"0.16326530612244897\"=>0.163265,\"0.20408163265306123\"=>0.204082,\"0.24489795918367346\"=>0.244898,\"0.2857142857142857\"=>0.285714,\"0.32653061224489793\"=>0.326531,\"0.3673469387755102\"=>0.367347…),Dict(2.0=>\"2.0\",1.59184=>\"1.5918367346938775\",0.122449=>\"0.12244897959183673\",1.95918=>\"1.9591836734693877\",1.22449=>\"1.2244897959183674\",1.63265=>\"1.6326530612244898\",0.693878=>\"0.6938775510204082\",1.10204=>\"1.1020408163265305\",1.79592=>\"1.7959183673469388\",0.367347=>\"0.3673469387755102\"…)),Any[],Any[],true,\"horizontal\")"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 18,
     "metadata": {
      "comm_id": "b38ee407-05d8-488a-87e3-eb74a74853d4",
      "reactive": true
     },
     "output_type": "execute_result"
    }
   ],
   "source": [
    "@manipulate for x1 in linspace(0, 2), x2 in linspace(0, 2)\n",
    "    settransform!(vis[:group1], Translation(x1, 0, 0))\n",
    "    settransform!(vis[:group1][:greenbox], Translation(x2, 1, 0))\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Likewise, we can delete an entire group:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "delete!(vis[:group1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Of course, we can draw much more interesting geometries than \n",
    "# just simple boxes. Let's load a 3D mesh and visualize it:\n",
    "using MeshIO\n",
    "using FileIO\n",
    "cat_mesh = load(joinpath(Pkg.dir(\"GeometryTypes\"), \"test\", \"data\", \"cat.obj\"))\n",
    "model = Visualizer(cat_mesh);\n",
    "settransform!(model, LinearMap(AngleAxis(pi/2, 1, 0, 0)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "delete!(model)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Visualizer with path prefix Symbol[] using LCM LCMCore.LCM(Ptr{Void} @0x00007ff9577dfe90,RawFD(71),LCMCore.Subscription[LCMCore.Subscription{LCMCore.SubscriptionOptions{DrakeVisualizer.Comms.CommsT,DrakeVisualizer.#handle_msg#7{DrakeVisualizer.CoreVisualizer}}}(LCMCore.SubscriptionOptions{DrakeVisualizer.Comms.CommsT,DrakeVisualizer.#handle_msg#7{DrakeVisualizer.CoreVisualizer}}(DrakeVisualizer.Comms.CommsT,DrakeVisualizer.handle_msg),Ptr{Void} @0x00007ff95923df70)])"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Next, let's create a triangulated mesh by finding\n",
    "# the 0-level set of some function. \n",
    "# \n",
    "# First, we'll define our function:\n",
    "f = x -> sum(sin, 5 * x)\n",
    "\n",
    "# Then we pick a region of interest in which to sample the function.\n",
    "# This region starts at (-1, -1, -1) and extends to (1, 1, 1):\n",
    "lower_bound = Vec(-1.,-1,-1)\n",
    "upper_bound = Vec(1., 1, 1)\n",
    "\n",
    "# Those two pieces of information are all we need to construct a robot\n",
    "# geometry. For this, we'll need the contour_mesh function:\n",
    "mesh = contour_mesh(f, lower_bound, upper_bound)\n",
    "# Under the hood, this will sample f at regularly spaced points inside\n",
    "# the bounding rectangle, then compute a surface that connects all the \n",
    "# points for which f(x) = 0.\n",
    "\n",
    "# And now we can load that geometry into the visualizer\n",
    "model = Visualizer(mesh)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [],
      "text/plain": [
       "Interact.Options{:SelectionSlider,Float64}(Signal{Float64}(0.0, nactions=1),\"iso_level\",0.0,\"0.0\",Interact.OptionDict(DataStructures.OrderedDict(\"-1.0\"=>-1.0,\"-0.96\"=>-0.96,\"-0.92\"=>-0.92,\"-0.88\"=>-0.88,\"-0.84\"=>-0.84,\"-0.8\"=>-0.8,\"-0.76\"=>-0.76,\"-0.72\"=>-0.72,\"-0.68\"=>-0.68,\"-0.64\"=>-0.64…),Dict(-0.92=>\"-0.92\",-0.28=>\"-0.28\",-0.04=>\"-0.04\",0.56=>\"0.56\",-0.32=>\"-0.32\",0.2=>\"0.2\",-0.68=>\"-0.68\",-0.96=>\"-0.96\",0.48=>\"0.48\",-0.8=>\"-0.8\"…)),Any[],Any[],true,\"horizontal\")"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "Visualizer with path prefix Symbol[] using LCM LCMCore.LCM(Ptr{Void} @0x00007ff95764f360,RawFD(77),LCMCore.Subscription[LCMCore.Subscription{LCMCore.SubscriptionOptions{DrakeVisualizer.Comms.CommsT,DrakeVisualizer.#handle_msg#7{DrakeVisualizer.CoreVisualizer}}}(LCMCore.SubscriptionOptions{DrakeVisualizer.Comms.CommsT,DrakeVisualizer.#handle_msg#7{DrakeVisualizer.CoreVisualizer}}(DrakeVisualizer.Comms.CommsT,DrakeVisualizer.handle_msg),Ptr{Void} @0x00007ff955289c10)])"
      ]
     },
     "execution_count": 23,
     "metadata": {
      "comm_id": "c962eaf9-073b-4520-b7af-c5b5eb218620",
      "reactive": true
     },
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# We can even manipulate the geometry by changing the iso level. \n",
    "# By default, contour_mesh constructs a mesh connecting the points \n",
    "# in space for which f(x) = 0, where 0 is called the isosurface level\n",
    "# or iso level. But we can change that iso level to any number we want:\n",
    "\n",
    "f = x -> sum(sin, 5 * x)\n",
    "lower_bound = Vec(-1.,-1,-1)\n",
    "upper_bound = Vec(1., 1, 1)\n",
    "\n",
    "@manipulate for iso_level in linspace(-1, 1, 51)\n",
    "    geometry = contour_mesh(f, lower_bound, upper_bound, iso_level)\n",
    "    model = Visualizer(geometry)\n",
    "end\n",
    "\n",
    "# Note that for high iso_level values our geometry gets cut off at the\n",
    "# edges. We could fix that by replacing the bounds with a bigger box. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "delete!(model)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Batching for Better Performance\n",
    "\n",
    "Each time you call `setgeometry!()`, `settransform!()`, or `delete!()`, there is some communication between Julia and the Drake Visualizer application. That communication can take time, so if you are loading or drawing many geometries simultaneously, then you may want to batch those operations. Batching is easy. Instead of doing this:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "vis = Visualizer()\n",
    "setgeometry!(vis[:group1][:box1], green_box)\n",
    "setgeometry!(vis[:group1][:box2], green_box)\n",
    "settransform!(vis[:group1], Translation(0, 1, 0))\n",
    "settransform!(vis[:group1][:box1], Translation(1, 0, 0))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Just put all the commands inside a call to `batch()`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "vis = Visualizer()\n",
    "batch(vis) do v\n",
    "    setgeometry!(v[:group1][:box1], green_box)\n",
    "    setgeometry!(v[:group1][:box2], green_box)\n",
    "    settransform!(v[:group1], Translation(0, 1, 0))\n",
    "    settransform!(v[:group1][:box1], Translation(1, 0, 0))\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The above syntax will perform exactly the same drawing operations, but will only send one message to the viewer at the end of the `batch()` call. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "delete!(vis)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# More Geometry Types\n",
    "\n",
    "`DrakeVisualizer` supports a few extra types of geometry that you may want to visualize. One such geometry is a point cloud: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Visualizer with path prefix Symbol[:pointcloud] using LCM LCMCore.LCM(Ptr{Void} @0x00007ff959c81870,RawFD(293),LCMCore.Subscription[LCMCore.Subscription{LCMCore.SubscriptionOptions{DrakeVisualizer.Comms.CommsT,DrakeVisualizer.#handle_msg#7{DrakeVisualizer.CoreVisualizer}}}(LCMCore.SubscriptionOptions{DrakeVisualizer.Comms.CommsT,DrakeVisualizer.#handle_msg#7{DrakeVisualizer.CoreVisualizer}}(DrakeVisualizer.Comms.CommsT,DrakeVisualizer.handle_msg),Ptr{Void} @0x00007ff953705e70)])"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# A PointCloud can be constructed from a vector of points.\n",
    "# The easiest way to represent a point is just a standard Julia vector:\n",
    "pointcloud = PointCloud([[x, 0, 0] for x in linspace(-1, 1)])\n",
    "setgeometry!(vis[:pointcloud], pointcloud)\n",
    "\n",
    "# For more efficient point clouds, try using a vector of\n",
    "# StaticArrays.SVector types. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "using ColorTypes: RGB"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Visualizer with path prefix Symbol[:pointcloud] using LCM LCMCore.LCM(Ptr{Void} @0x00007ff959c81870,RawFD(293),LCMCore.Subscription[LCMCore.Subscription{LCMCore.SubscriptionOptions{DrakeVisualizer.Comms.CommsT,DrakeVisualizer.#handle_msg#7{DrakeVisualizer.CoreVisualizer}}}(LCMCore.SubscriptionOptions{DrakeVisualizer.Comms.CommsT,DrakeVisualizer.#handle_msg#7{DrakeVisualizer.CoreVisualizer}}(DrakeVisualizer.Comms.CommsT,DrakeVisualizer.handle_msg),Ptr{Void} @0x00007ff953705e70)])"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# PointClouds can also have \"channels\" which describe their\n",
    "# data. One useful channel is the :rgb channel:\n",
    "delete!(vis[:pointcloud])\n",
    "pointcloud.channels[:rgb] = [RGB(0, g, 0) for g in linspace(0, 1)]\n",
    "setgeometry!(vis[:pointcloud], pointcloud)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "delete!(vis)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Close the viewer:\n",
    "# kill(proc)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Julia 0.6.0-rc3",
   "language": "julia",
   "name": "julia-0.6"
  },
  "language_info": {
   "file_extension": ".jl",
   "mimetype": "application/julia",
   "name": "julia",
   "version": "0.6.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
